#include "Servidor.h"


Servidor :: Servidor ( char* archivo,char letra ) {
	this->cola = new Cola<mensaje> ( archivo,letra );
	this->proximoIdSala = 1;
}

Servidor :: ~Servidor () {
	delete this->cola;
}

int Servidor :: recibirPeticion () {
	this->cola->leer ( PETICION,&(this->peticionRecibida) );
	return 0;
}

int Servidor :: procesarPeticion () {
	int idSala = 0;
	this->respuesta.tipoMensaje = this->peticionRecibida.tipoMensaje ;
//	cout << "Se recibio la peticion " << this->peticionRecibida.tipoMensaje << " de " << this->peticionRecibida.nombreEmisor << endl;
	switch(this->peticionRecibida.tipoMensaje){
		case 'D': //Obtener clientes de sala
			memset(this->respuesta.texto,'\0',TEXTO_SIZE);
			if (existeSala(this->peticionRecibida.idSala) == false) {
				this->respuesta.idSala = -1;
			}else{
				strcpy(this->respuesta.texto,this->obtenerClientesDeSala(this->peticionRecibida.idSala).c_str());
				this->respuesta.tipoMensaje = 'D';
				this->respuesta.idSala = this->peticionRecibida.idSala;
			}
			break;
		case 'P':
			memset(this->respuesta.texto,'\0',TEXTO_SIZE);
			strcpy(this->respuesta.texto,this->obtenerSalasAEnviar().c_str());
			this->respuesta.tipoMensaje = 'P';
			break;//Pedido de salas
		case 'S':
			this->borrarClienteDeSala(this->peticionRecibida.idSala,this->peticionRecibida.pid);
			this->respuesta.tipoMensaje = 'S';
			break;//Salir
		case 'U':
			cout << "IDSALA:" << this->peticionRecibida.idSala << endl;
			if (existeSala(this->peticionRecibida.idSala) == false) {
				this->respuesta.idSala = -1;
			}else{
				this->agregarClienteASala(this->peticionRecibida.idSala,this->peticionRecibida.pid,this->peticionRecibida.nombreEmisor);
				this->respuesta.idSala = this->peticionRecibida.idSala;
			}
			break;//Unirse a una sala
		case 'A':
			idSala = this->crearNuevaSala(this->peticionRecibida.texto);
			this->agregarClienteASala(idSala,this->peticionRecibida.pid,this->peticionRecibida.nombreEmisor);
			this->respuesta.idSala = idSala;
			this->respuesta.tipoMensaje = 'A';
			break;//Agregar nueva sala
	}

	this->respuesta.mtype = this->peticionRecibida.pid;

	return 0;
}

int Servidor :: responderPeticion () {
	if (this->peticionRecibida.tipoMensaje == 'C') {
		for (list<Sala*>::iterator itSala=this->salas.begin(); itSala!=this->salas.end(); itSala++){
			if (((Sala*)*itSala)->getId() == this->peticionRecibida.idSala) {
				list<ClienteRemoto*> clientes = ((Sala*)*itSala)->getClientes();

				for (list<ClienteRemoto*>::iterator itCliente = clientes.begin(); itCliente!=clientes.end(); itCliente++){
					if (((ClienteRemoto*)*itCliente)->getPid() != this->peticionRecibida.pid) {
						this->respuesta.mtype = ((ClienteRemoto*)*itCliente)->getPid();
						this->respuesta.tipoMensaje = 'C';
						strcpy(this->respuesta.nombreEmisor,this->peticionRecibida.nombreEmisor);
						strcpy(this->respuesta.texto,this->peticionRecibida.texto);
						this->cola->escribir(this->respuesta);
					}
				}
			}
		}

	} else {
		this->respuesta.pid = this->peticionRecibida.pid;
		this->cola->escribir ( this->respuesta );
	}

	return 0;
}

mensaje Servidor :: getPeticionRecibida () {
	return this->peticionRecibida;
}

mensaje Servidor :: getRespuesta () {
	return this->respuesta;
}

string Servidor :: obtenerSalasAEnviar(){
	string salasAEnviar = "";
	char buffer[10];
	for (list<Sala*>::iterator it=this->salas.begin(); it!=this->salas.end(); ++it){
		sprintf(buffer, "%d",((Sala*)*it)->getId() );
		salasAEnviar.append(buffer);
		salasAEnviar.append("|");
		salasAEnviar.append(((Sala*)*it)->getNombre());
		salasAEnviar.append(",");
	}
	return salasAEnviar;
}

int Servidor :: crearNuevaSala(string nombre){
	Sala* nuevaSala = new Sala(nombre,this->proximoIdSala++);
	this->salas.push_back(nuevaSala);
	return this->proximoIdSala - 1;
}

void Servidor :: agregarClienteASala(int idSala,int pidCliente,string nombreCliente){
	for (list<Sala*>::iterator it=this->salas.begin(); it!=this->salas.end(); ++it){
		if (((Sala*)*it)->getId() == idSala) {
			ClienteRemoto* nuevoClienteRemoto = new ClienteRemoto(pidCliente,nombreCliente);
			((Sala*)*it)->agregarCliente(nuevoClienteRemoto);
		}
	}
}

void Servidor :: borrarClienteDeSala(int idSala, int pidCliente){
	bool hayClientes = true;
	for (list<Sala*>::iterator it=this->salas.begin(); it!=this->salas.end(); ++it){
		if (((Sala*)*it)->getId() == idSala) {
			((Sala*)*it)->borrarCliente(pidCliente);
			hayClientes = ((Sala*)*it)->hayClientes();
		}
	}

	if (hayClientes == false) {
		this->borrarSala(idSala);
	}
}

void Servidor::borrarSala(int idSala){
	bool borrado = false;

	for (list<Sala*>::iterator it=this->salas.begin(); it!=this->salas.end() && !borrado; it++){
		if(((Sala*)*it)->getId() == idSala){
			this->salas.erase(it);
			borrado = true;
		}
	}
}

string Servidor :: obtenerClientesDeSala(int idSala){
	string clientesAEnviar = "";


	for (list<Sala*>::iterator itSala=this->salas.begin(); itSala!=this->salas.end(); itSala++){
		if (((Sala*)*itSala)->getId() == idSala) {
			list<ClienteRemoto*> clientes = ((Sala*)*itSala)->getClientes();
			for (list<ClienteRemoto*>::iterator itCliente = clientes.begin(); itCliente!=clientes.end(); itCliente++){
				clientesAEnviar.append(((ClienteRemoto*)*itCliente)->getNombre());
				clientesAEnviar.append(",");
			}
		}
	}
	cout << "Clientes a enviar: " << clientesAEnviar << endl;
	return clientesAEnviar;
}

bool Servidor::existeSala(int idSala){
	bool existe = false;
	for (list<Sala*>::iterator itSala=this->salas.begin(); itSala!=this->salas.end() && !existe; itSala++){
		if (((Sala*)*itSala)->getId() == idSala) {
			existe = true;
		}
	}

	return existe;
}

